/* Nate Deisinger (ndeisinger@wisc.edu)
 *
 * This file is part of soot-csi, a project to apply lightweight
 * instrumentation to Java programs to facilitate debugging through
 * the Soot analysis framework.
 *
 * Copyright (c) 2014, Nate Deisinger, University of Wisconsin-Madison
 *   Madison, Wisconsin 53715
 *   All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor,
 *   Boston, MA  02110-1301
 *   USA
 * or retrieve version 2.1 at their website:
 *   http://www.gnu.org/licenses/lgpl-2.1.html
 */
package uwmadison.soot.analysis;

import java.util.HashMap;
import java.util.LinkedList;

import soot.Unit;
import soot.toolkits.graph.Block;
import uwmadison.soot.analysis.PathAnalysis.DUMMY_TYPE;

/**
 * A class representing a node in our CFG.
 * @author Nate Deisinger
 */
public class CFGNode
{
    private Block block;
    private HashMap<CFGNode, CFGEdge> predEdges;
    private HashMap<CFGNode, CFGEdge> succEdges;
    private LinkedList<CFGEdge> backEdges;
    private LinkedList<CFGNode> predecessors;
    private LinkedList<CFGNode> successors;
    private DUMMY_TYPE type;

    public CFGNode(Block block)
    {
        predEdges = new HashMap<CFGNode, CFGEdge>();
        succEdges = new HashMap<CFGNode, CFGEdge>();
        predecessors = new LinkedList<CFGNode>();
        successors = new LinkedList<CFGNode>();
        backEdges = new LinkedList<CFGEdge>();
        this.block = block;
        this.type = DUMMY_TYPE.NON_DUMMY;
    }

    public CFGNode()
    {
        predEdges = new HashMap<CFGNode, CFGEdge>();
        succEdges = new HashMap<CFGNode, CFGEdge>();
        predecessors = new LinkedList<CFGNode>();
        successors = new LinkedList<CFGNode>();
        backEdges = new LinkedList<CFGEdge>();
        this.block = new Block(null, null, null, -1, -1, null);
        this.type = DUMMY_TYPE.NON_DUMMY;
    }

    public CFGNode(DUMMY_TYPE type)
    {
        predEdges = new HashMap<CFGNode, CFGEdge>();
        succEdges = new HashMap<CFGNode, CFGEdge>();
        predecessors = new LinkedList<CFGNode>();
        successors = new LinkedList<CFGNode>();
        backEdges = new LinkedList<CFGEdge>();
        if (type == DUMMY_TYPE.ENTRY)
        {
            this.block = new Block(null, null, null, PathAnalysis.ENTRY_DUMMY, -1, null);
        }
        else
        {
            this.block = new Block(null, null, null, PathAnalysis.EXIT_DUMMY, -1, null);
        }
        this.type = type;
    }

    public Block getBlock()
    {
        return block;
    }

    public boolean addPred(CFGNode pred)
    {
        return predecessors.add(pred);
    }

    public boolean addSucc(CFGNode succ)
    {
        return successors.add(succ);
    }

    public CFGEdge addPredEdge(CFGEdge predEdge)
    {
        return predEdges.put(predEdge.getFrom(), predEdge);
    }

    public CFGEdge addSuccEdge(CFGEdge succEdge)
    {
        return succEdges.put(succEdge.getTo(), succEdge);
    }

    public HashMap<CFGNode, CFGEdge> getPredEdges()
    {
        return predEdges;
    }

    public HashMap<CFGNode, CFGEdge> getSuccEdges()
    {
        return succEdges;
    }

    public LinkedList<CFGNode> getPreds()
    {
        return predecessors;
    }

    public LinkedList<CFGNode> getSuccs()
    {
        return successors;
    }

    public boolean isDummy()
    {
        return this.type != DUMMY_TYPE.NON_DUMMY;
    }

    public int getBlockID()
    {
        return block.getIndexInMethod();
    }

    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        sb.append("Block ID: " + block.getIndexInMethod() + "\n");
        sb.append("Predecessors: ");
        for (CFGNode n : predecessors)
        {
            sb.append(n.getBlockID() + " ");
        }
        sb.append("\n");
        sb.append("Successors: ");
        for (CFGNode n : successors)
        {
            sb.append(n.getBlockID() + " ");
        }
        sb.append("\n");
        return sb.toString();
    }

    public void addBackedge(CFGEdge backEdge)
    {
        backEdges.add(backEdge);
    }

    public LinkedList<CFGEdge> getBackedges()
    {
        return backEdges;
    }

}